﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using QMERP.Domain.Dtos;
using QMERP.Domain.Entities;
using QMERP.Domain.Enums;
using QMERP.Infrastructure.CustomException;
using QMERP.Infrastructure.EFCore;
using QMERP.Infrastructure.EFCore.Extensions;
using QMERP.Infrastructure.Extensions;
using QMERP.Infrastructure.Security;
using System.Data;

namespace QMERP.Application.Services
{
    public class PurchaseOrderService : IPurchaseOrderService
    {
        private readonly IMapper _mapper;
        private readonly QMERPDbContext _db;
        private readonly ISerialNumberService _serialNumberSvc;
        private readonly ICurrentUser _currentUser;
        public PurchaseOrderService(IMapper mapper, QMERPDbContext db, ISerialNumberService serialNumberSvc, ICurrentUser currentUser)
        {
            _mapper = mapper;
            _db = db;
            _serialNumberSvc = serialNumberSvc;
            _currentUser = currentUser;
        }
        /// <summary>
        /// 采购单窗体
        /// </summary>
        /// <returns></returns>
        public async Task<PageResponse<PurchaseOrderResponse>> Query(PageRequest<PurchaseOrderRequest> request)
        {
            var response = new PageResponse<PurchaseOrderResponse>();
            var query = Where(request);
            var list = await query.Paging(request.PageIndex, request.PageSize).ToListAsync();
            response.TotalCount = await query.CountAsync();
            response.PageIndex = request.PageIndex;
            response.PageSize = request.PageSize;
            response.List = _mapper.Map<List<PurchaseOrderResponse>>(list);
            return response;
        }
        /// <summary>
        /// 获取id的采购单详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<PurchaseOrderResponse> Detail(long id)
        {
            var model = await _db.PurchaseOrder
                .Include(x => x.PurchaseOrderDetails).ThenInclude(x => x.PurchaseOrderDetail_LensDetails)
                .Include(x => x.PurchaseOrderDetails).ThenInclude(x => x.Supplier)
                .Include(x => x.PurchaseOrderDetails).ThenInclude(x => x.Warehouse)
                .Include(x => x.PurchaseOrderDetails).ThenInclude(x => x.Lens).AsNoTracking().FindByIdAsync(id);
            var response = _mapper.Map<PurchaseOrderResponse>(model);
            return response;
        }
        /// <summary>
        /// 采购单保存
        /// </summary>
        /// <param name="request"></param>
        /// <param name="isCheck"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task<PurchaseOrderResponse> Save(PurchaseOrderSaveRequest request, bool isCheck = false)
        {
            if (request.PurchaseOrderDetails.Count <= 0)
                throw new ApiException("请填写镜种信息!");

            for (int i = 0; i < request.PurchaseOrderDetails.Count; i++)
            {
                string col = $"第{i + 1}行:";
                var detail = request.PurchaseOrderDetails[i];
                if (detail.LensDetails.Count <= 0)
                    throw new ApiException($"{col}请导入XY表!");

                if (detail.LensDetails.Sum(s => s.Qty) <= 0)
                    throw new ApiException($"{col}XY表总片数为0,请检查!");

                var stock = await (from a in _db.Stock.Include(x => x.StockDetails).Include(x => x.Lens)
                                   join b in _db.Lens_Supplier on a.LensId equals b.LensId
                                   where b.SupplierId == detail.SupplierId && a.WarehouseId == detail.WarehouseId && a.LensId == detail.LensId
                                   select a
                                   ).FirstOrDefaultAsync();

                if (stock == null)
                    throw new ApiException($"{col}此供应商仓库的库存镜种不存在!");

                if (!detail.LensDetails.InRange(_mapper.Map<LensResponse>(stock.Lens)))
                    throw new ApiException($"{col}XY表度数超出镜种范围!");

                detail.LensDetails = detail.LensDetails.Where(x => x.Qty > 0).ToList();
            }

            PurchaseOrder? model;
            if (request.Id == null)
            {
                string number = await _serialNumberSvc.GetSerialNumber(SerialNumberTypeEnum.PurchaseOrder);
                model = _mapper.Map<PurchaseOrder>(request);
                model.Number = number;
                //model.SequenceNumber = GetNewSequenceNumber(request.SupplierId, request.WarehouseId);
                model.Status = PurchaseOrderStatusEnum.Pending.ToString();
                await _db.AddAsync(model);
            }
            else
            {
                model = await _db.PurchaseOrder.Include(x => x.PurchaseOrderDetails).FindByIdAsync(request.Id.Value);
                if (model == null)
                    throw new ApiException("采购单不存在!");
                model.CustomerOrderNumber = request.CustomerOrderNumber;
                model.Remark = request.Remark;
                model.PurchaseOrderDetails = _mapper.Map<List<PurchaseOrderDetail>>(request.PurchaseOrderDetails);
            }
            if (isCheck)
                Check(model);
            await _db.SaveChangesAsync();
            return _mapper.Map<PurchaseOrderResponse>(model);
        }
        /// <summary>
        /// 采购单审核
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public async Task Check(long[] ids)
        {
            if (ids == null)
                throw new ApiException("id不能为空!");

            var list = await _db.PurchaseOrder.Where(x => ids.Contains(x.Id)).ToListAsync();
            foreach (var order in list)
            {
                if (order.Status != PurchaseOrderStatusEnum.Pending.ToString())
                    throw new ApiException($"采购单{order.Number}不能审核!");
                Check(order);
            }
            await _db.SaveChangesAsync();
        }
        /// <summary>
        /// 采购单弃审
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public async Task UnCheck(long[] ids)
        {
            if (ids == null)
                throw new ApiException("id不能为空!");

            var list = await _db.PurchaseOrder.Where(x => ids.Contains(x.Id)).ToListAsync();
            foreach (var l in list)
            {
                if (l.Status != PurchaseOrderStatusEnum.Receive.ToString())
                    throw new ApiException($"采购单{l.Number}不能弃审!");

                if (await _db.EnterStockOrder.AnyAsync(x => x.BusinessOrderType == EnterStockBusinessOrderTypeEnum.PurchaseOrder.ToString() && x.BusinessOrderId == l.Id && x.Status != EnterStockOrderStatusEnum.Canceled.ToString()))
                    throw new ApiException($"采购单{l.Number}不能弃审,已添加入库单!");

                l.Status = PurchaseOrderStatusEnum.Pending.ToString();
                l.CheckedBy = null;
                l.CheckedByName = null;
                l.CheckedOn = null;
            }
            await _db.SaveChangesAsync();
        }
        /// <summary>
        /// 采购单取消
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public async Task Cancel(long[] ids)
        {
            if (ids == null)
                throw new ApiException("id不能为空!");

            var list = await _db.PurchaseOrder.Where(x => ids.Contains(x.Id)).ToListAsync();
            foreach (var l in list)
            {
                if (l.Status != PurchaseOrderStatusEnum.Pending.ToString() || l.Status != PurchaseOrderStatusEnum.Receive.ToString())
                    throw new ApiException($"采购单{l.Number}不能取消!");

                if (await _db.EnterStockOrder.AnyAsync(x => x.BusinessOrderType == EnterStockBusinessOrderTypeEnum.PurchaseOrder.ToString() && x.BusinessOrderId == l.Id && x.Status != EnterStockOrderStatusEnum.Canceled.ToString()))
                    throw new ApiException($"采购单{l.Number}不能取消,已添加入库单!");

                l.Status = PurchaseOrderStatusEnum.Canceled.ToString();
            }
            await _db.SaveChangesAsync();
        }

        /// <summary>
        /// 获取采购单主要信息列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<List<PurchaseOrderMainInfoResponse>> GetPurchaseOrderMainInfos(PageRequest<PurchaseOrderRequest> request)
        {
            var orders = await Where(request).ToListAsync();
            var details = orders.SelectMany(s => s.PurchaseOrderDetails).ToList();
            return _mapper.Map<List<PurchaseOrderMainInfoResponse>>(details);
        }

        private IQueryable<PurchaseOrder> Where(PageRequest<PurchaseOrderRequest> request)
        {
            IQueryable<PurchaseOrder> query = _db.PurchaseOrder
                .Include(x => x.PurchaseOrderDetails).ThenInclude(x => x.PurchaseOrderDetail_LensDetails)
                .Include(x => x.PurchaseOrderDetails).ThenInclude(x => x.Supplier)
                .Include(x => x.PurchaseOrderDetails).ThenInclude(x => x.Warehouse)
                .Include(x => x.PurchaseOrderDetails).ThenInclude(x => x.Lens).AsNoTracking();
            if (!request.Query.Number.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.Number.Contains(request.Query.Number!));
            }
            if (!request.Query.CustomerOrderNumber.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.CustomerOrderNumber.Contains(request.Query.CustomerOrderNumber!));
            }
            if (!request.Query.CreatedByName.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.CreatedByName.Contains(request.Query.CreatedByName!));
            }
            if (request.Query.CreatedOnStart != null)
            {
                query = query.Where(x => x.CreatedOn >= request.Query.CreatedOnStart.Value.ToStart());
            }
            if (request.Query.CreatedOnEnd != null)
            {
                query = query.Where(x => x.CreatedOn <= request.Query.CreatedOnEnd.Value.ToEnd());
            }
            if (!request.Query.Status.IsNullOrWhiteSpace())
            {
                query = query.Where(x => x.Status == request.Query.Status);
            }
            if (request.Query.SupplierId != null)
            {
                query = query.Where(x => x.PurchaseOrderDetails.Select(s => s.SupplierId).Contains(request.Query.SupplierId.Value));
            }
            if (request.Query.WarehouseId != null)
            {
                query = query.Where(x => x.PurchaseOrderDetails.Select(s => s.WarehouseId).Contains(request.Query.WarehouseId.Value));
            }
            if (request.Query.LensId != null)
            {
                query = query.Where(x => x.PurchaseOrderDetails.Select(s => s.LensId).Contains(request.Query.LensId.Value));
            }
            //if (request.Query.Status == PurchaseOrderStatusEnum.Pending.ToString())
            //{
            //    query = query.OrderByDescending(x => x.CreatedOn);
            //}
            //else if (request.Query.Status == PurchaseOrderStatusEnum.Receive.ToString())
            //{
            //    query = query.OrderByDescending(x => x.CheckedOn);
            //}
            //else if (request.Query.Status == PurchaseOrderStatusEnum.Finished.ToString())
            //{
            //    query = query.OrderByDescending(x => x.FinishedOn);
            //}
            //else
            //{
            //    query = query.OrderByDescending(x => x.UpdatedOn);
            //}
            query = query.OrderByDescending(x => x.CreatedOn);
            return query;
        }
        private void Check(PurchaseOrder order)
        {
            order.Status = PurchaseOrderStatusEnum.Receive.ToString();
            order.CheckedBy = _currentUser.Id;
            order.CheckedByName = _currentUser.Name;
            order.CheckedOn = DateTime.Now;
        }
        //private string GetNewSequenceNumber(long supplierId, long warehouseId)
        //{
        //    string nowMonthOne = DateTime.Now.ToString("yyyy-MM-01") + " 00:00:00";
        //    string nextMonthOne = DateTime.Now.AddMonths(1).ToString("yyyy-MM-01") + " 00:00:00";
        //    string yearMonth = DateTime.Now.ToString("yyyyMM").Substring(2, 4);

        //    var models = _db.PurchaseOrder.Where(x => x.SupplierId == supplierId && x.CreatedOn >= Convert.ToDateTime(nowMonthOne) && x.CreatedOn <= Convert.ToDateTime(nextMonthOne)).FirstOrDefault();
        //    string supplierStr = "0000";
        //    if (models != null)
        //    {
        //        string[] sqNumberSp = models.SequenceNumber.Split('_');
        //        if (sqNumberSp.Count() >= 3)
        //        {
        //            supplierStr = sqNumberSp[1].Substring(4, sqNumberSp[1].Length - 4);
        //        }
        //    }
        //    string newSupplierInt = (Convert.ToInt32(supplierStr) + 1).ToString().PadLeft(4, '0');
        //    var modelw = _db.PurchaseOrder.Where(x => x.WarehouseId == warehouseId && x.CreatedOn >= Convert.ToDateTime(nowMonthOne) && x.CreatedOn <= Convert.ToDateTime(nextMonthOne)).FirstOrDefault();
        //    string wareStr = "0000";
        //    if (modelw != null) 
        //    {
        //        string[] sqNumberSp = modelw.SequenceNumber.Split('_');
        //        if (sqNumberSp.Count() >= 3)
        //        {
        //            wareStr = sqNumberSp[2].Substring(4, sqNumberSp[2].Length - 4);
        //        }
        //    }
        //    var supplier = _db.Supplier.FindById(supplierId);
        //    var warehouse = _db.Warehouse.FindById(warehouseId);
        //    string newWareInt = (Convert.ToInt32(wareStr) + 1).ToString().PadLeft(4, '0');
        //    string newSequenceNumber = yearMonth + "_" + supplier.Code + newSupplierInt + "_" + warehouse.Code + newWareInt;
        //    return newSequenceNumber;
        //}
    }
}
